package model.symbol;

import lang.Language;
import lang.asm.DataTypeUtil;
import model.code.CodeFileChunk;
import model.code.Rowable;
import model.code.Structure;
import model.code.line.NameLine;
import model.code.line.SingleLine;
import model.code.line.TypeLine;
import model.code.line.ValueLine;

/**
 * This class is for members of {@link model.code.Structure}s.
 *
 * @author Neil Dickson
 */
public class StructureMember extends Rowable implements Symbol, SingleLine.LineObserver {
	private final long		id;

	/**
	 * This is because Java can't do virtual static functions
	 */
	public static final StructureMember	DUMMY = new StructureMember("","","","",null,0);

	public static final int	NAME_INDEX			= 0;
	public static final int	TYPE_INDEX			= 1;
	public static final int	INITIAL_VALUE_INDEX	= 2;
	public static final int	DESCRIPTION_INDEX	= 3;
	public static final int	NUM_STRINGS			= 4;

	public StructureMember(String name, String type, String initialValue, String description, CodeFileChunk parent, int row) {
		super(NUM_STRINGS,parent,CodeFileChunk.LOCATION_STRUCTURE_MEMBERS,row);
		id = Scope.getUniqueID();
		strings[NAME_INDEX] = new NameLine(name.toCharArray(),parent,CodeFileChunk.LOCATION_STRUCTURE_MEMBERS,(row<<16)+NAME_INDEX,this);
		strings[TYPE_INDEX] = new TypeLine(type.toCharArray(),parent,CodeFileChunk.LOCATION_STRUCTURE_MEMBERS,(row<<16)+TYPE_INDEX);
		strings[INITIAL_VALUE_INDEX] = new ValueLine(initialValue.toCharArray(),parent,CodeFileChunk.LOCATION_STRUCTURE_MEMBERS,(row<<16)+INITIAL_VALUE_INDEX);
		strings[DESCRIPTION_INDEX] = new SingleLine(description.toCharArray(),parent,CodeFileChunk.LOCATION_STRUCTURE_MEMBERS,(row<<16)+DESCRIPTION_INDEX);
		getInitialValue().addObserver(this);
	}

	public StructureMember copy(CodeFileChunk parent,int row) {
		return new StructureMember(getName().toString(),getType().toString(),getInitialValue().toString(),getDescription().toString(),parent,row);
	}

	public Structure getParent() {
		return (Structure)getName().getParent();
	}

	public NameLine getName() {
		return (NameLine)strings[NAME_INDEX];
	}

	public SingleLine getDescription() {
		return strings[DESCRIPTION_INDEX];
	}

	public TypeLine getType() {
		return (TypeLine)strings[TYPE_INDEX];
	}

	public long getID() {
		return id;
	}

	public ValueLine getInitialValue() {
		return (ValueLine)strings[INITIAL_VALUE_INDEX];
	}

	/**
	 * Determines the size of the structure member's type.
	 * @return size in bytes of the StructureMember's type, or 0 if erroneous
	 */
	public int getTypeSize() {
		if (getInitialValue().getParent()!=null) {
			Structure structure = (Structure)getInitialValue().getParent();
			Language language = structure.getLanguage();
			DataType dataType = DataTypeUtil.getDataType(getType().toString(),language.getScope(),structure.getGlobalScope(),structure.getMode());
			if (dataType!=null) {
				return dataType.getSize();
			}
		}
		return 0;
	}

	/**
	 * Determines the total size of the structure member by parsing its value and looking at its type.
	 * @return total size in bytes of the StructureMember, or 0 if erroneous
	 */
	public int getTotalSize() {
		if (getInitialValue().getParent()!=null) {
			Structure structure = (Structure)getInitialValue().getParent();
			Language language = structure.getLanguage();
			if (language!=null) {
				DataType dataType = DataTypeUtil.getDataType(getType().toString(),language.getScope(),structure.getGlobalScope(),structure.getMode());
				if (dataType!=null) {
					Object sizeOrError = language.getParser().evaluateArray(getInitialValue(),dataType,null,null,0,getInitialValue().getNumReferences());
					if (sizeOrError!=null && sizeOrError instanceof Integer) {
						return (Integer)sizeOrError;
					}
				}
			}
		}
		return 0;
	}


	public String toString() {
		return getName().toString();
	}

	public void nowHaveGlobalScope() {
		getType().reparse();
		getInitialValue().reparse();
	}

	public void valueChanged(SingleLine line, String oldValue) {
		getInitialValue().reparse();
	}
}
